#pragma once

#include <string>
#include "grpc++/grpc++.h"
#include "../GrpcModule/GrpcModule.grpc.pb.h"
#include "EnclaveProvider.h"
#include "Config.h"
#include <map>
#include <memory>
#include "../Base/CriticalSection.h"

class Service: public enclave::EnclaveServer::Service
{
public:
    Service(const std::string &config_file, std::shared_ptr<EnclaveProvider> enclave_provider);
    ~Service();

    void start();

    virtual ::grpc::Status ImportData(::grpc::ServerContext* context, const ::enclave::ImportDataRequest* request, ::grpc::ServerWriter< ::enclave::ImportDataResponse>* writer) override;
    virtual ::grpc::Status Search(::grpc::ServerContext* context, const ::enclave::searchRequest* request, ::grpc::ServerWriter< ::enclave::Rows>* writer) override;

    virtual ::grpc::Status SyncCmd(::grpc::ServerContext* context, const ::enclave::SyncCmdRequest* request, ::enclave::SyncCmdResponse* response) override;
    virtual ::grpc::Status SyncNotify(::grpc::ServerContext* context, const ::enclave::SyncNotifyRequest* request, ::enclave::SyncTablesDatas* response) override;
    virtual ::grpc::Status SyncInfo(::grpc::ServerContext* context, const ::enclave::SyncTablesDatas* request, ::enclave::SyncInfoResponse* response) override;
    virtual ::grpc::Status SyncData(::grpc::ServerContext* context, ::grpc::ServerReader< ::enclave::SyncTableRows>* reader, ::enclave::SyncDataResponse* response) override;
	virtual ::grpc::Status SyncFinished(::grpc::ServerContext* context, const ::enclave::SyncFinishedRequest* request, ::enclave::SyncFinishedResponse* response) override;

	virtual ::grpc::Status PubEncrypt(::grpc::ServerContext* context, const ::enclave::Rows* request, ::enclave::Rows* response) override;
	virtual ::grpc::Status PriDecrypt(::grpc::ServerContext* context, const ::enclave::Rows* request, ::enclave::Rows* response) override;
	virtual ::grpc::Status Encrypt(::grpc::ServerContext* context, const ::enclave::Fields* request, ::enclave::Fields* response) override;
	virtual ::grpc::Status Decrypt(::grpc::ServerContext* context, const ::enclave::Fields* request, ::enclave::Fields* response) override;

protected:
	std::shared_ptr<EnclaveProvider> get_enclave_porvider(const std::string &id);

public:
    Config config_;

private:
	std::shared_ptr<EnclaveProvider> enclave_provider_;

	std::map<std::string, std::shared_ptr<EnclaveProvider>> enclave_providers_map_;

	CriticalSection cs_;
};

